package com.why.client;


import com.why.channel.GetChannel;
import com.why.enums.ErrorEnum;
import com.why.exception.RpcException;

import com.why.message.RpcRequest;
import com.why.message.RpcResponse;
import com.why.nacos.ServiceRegistry;
import com.why.serializable.CommonSerializable;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * @program: why-rpc-framework
 * @description:
 * @author: @why
 * @create: 2021-03-15 17:16
 **/
@Slf4j
public class NettyRpcClient implements Client {

    private  ServiceRegistry registry;

    private  CommonSerializable serializable;
    public NettyRpcClient(ServiceRegistry registry, CommonSerializable serializable) {
        this.registry=registry;
        this.serializable = serializable;
    }



    @Override
    public Object sendRequest(RpcRequest request) {
        try {
            log.info("开始去注册中心获取服务提供者的信息。。。");
            String interfaceName = request.getInterfaceName();
            InetSocketAddress address = registry.getService(interfaceName);
            log.info("成功从注册中心获取到服务提供者的位置{}:",address.getAddress());
            log.info("开始去连接...");
            Channel channel = GetChannel.getChannel(serializable, address);

            if (channel != null) {
                log.info("连接成功，开始去发送请求信息。。。");
                //写出数据，并添加监听
                channel.writeAndFlush(request).addListener(future -> {
                    //添加监听
                    if (future.isSuccess()) {

                        log.info("发送请求成功！,请求信息为{}", request.toString());
                    } else {
                        log.info("客户端发送信息失败！");
                        throw new RpcException(ErrorEnum.CLIENT_UNKNOWN_ERROR);
                    }
                });

                //阻塞直到 Channel 关闭
                channel.closeFuture().sync();

                /**
                 * 等待发送数据时启动，channel 将 RpcRequest 对象写出，并且等待服务端返回的结果。
                 * 注意这里的发送是非阻塞的，所以发送后会立刻返回，而无法得到结果。
                 * 这里通过 AttributeKey 的方式阻塞获得返回结果：
                 */

                /**
                 * handler将数据存放在了AttributeKey，我们去那里获取。
                 */
                AttributeKey<RpcResponse> key = AttributeKey.valueOf("rpcResponse");
                System.out.println("key为\t"+key);
                RpcResponse rpcResponse = channel.attr(key).get();

                log.info("成功接收到请求信息,{}", rpcResponse);
                return rpcResponse.getData();
            }
        } catch (InterruptedException e) {
            throw new RuntimeException("InterruptedException 发生在客户端！");
        }

        return null;
    }
}